import re
import os
import matplotlib.pyplot as plt
import openpyxl
import networkx as nx


def parse_meta_yaml(meta_file):
    with open(meta_file, 'r') as f:
        try:
            meta_content = f.read()
            return meta_content
        except (ModuleNotFoundError, UnicodeDecodeError) as ex:
            print(meta_file)


# 解析meta.yaml文件找到依赖
def extract_requirements(meta_content, req_type):
    pattern = fr"{req_type}:(\s*- .+)"
    match = re.search(pattern, meta_content, re.DOTALL)
    if match:
        req_lines = match.group(1).split('\n')[1:]
        requirements = []
        for line in req_lines:
            line = line.strip()
            if line and line[0] != '-':
                break
            line = line.lstrip('- ')
            if line.startswith("{"):
                continue
            if line.startswith("'"):
                line = line.split()[0].strip("'")
            line = line.split(">")[0]
            line = line.split("=")[0]
            line = line.split("#")[0]
            line = line.split(" ")[0]
            _path = os.path.join(recipes_folder_path, line)
            if os.path.exists(_path):
                requirements.append(line)
        return requirements
    return []


# 遍历添加host依赖
def build_dependency_graph(host_reqs, run_reqs, build_reqs):
    graph = nx.DiGraph()
    package_name = f"{name.lower()}"
    node_name = package_name
    graph.add_node(node_name)

    all_reqs = host_reqs + run_reqs + build_reqs
    added_edges = set()

    for req in all_reqs:
        if (node_name, req) not in added_edges:
            graph.add_edge(node_name, req)
            added_edges.add((node_name, req))
    return graph


# 根据依赖构建图
def build_graph(folder_name):
    if folder_name in package_set:
        return
    folder_name = folder_name.strip()
    global name
    meta_yaml_path = os.path.join(recipes_folder_path, folder_name, "meta.yaml")
    if os.path.exists(meta_yaml_path):
        package_set.add(folder_name)
        meta_content = parse_meta_yaml(meta_yaml_path)
        if meta_content is None:
            return
        name_match = re.search(r"set\s+name\s*=\s*\"([^\"]+)\"",meta_content)
        if name_match:
            name = name_match.group(1)
        host_reqs = extract_requirements(meta_content,'host')
        run_reqs = extract_requirements(meta_content, 'run')
        build_reqs = extract_requirements(meta_content, 'build')
        graph = build_dependency_graph(host_reqs,run_reqs,build_reqs)
        merged_graph.add_edges_from(graph.edges)
        merged_graph.add_nodes_from(graph.nodes)

        for host in host_reqs:
            build_graph("" + host)
        for run in run_reqs:
            build_graph("" + run)
        for build in build_reqs:
            build_graph("" + build)

recipes_folder_path = 'D:\\hainan\\bioconda-recipes\\recipes'
excel_file = 'D:\\hainan\\bioconda.xlsx'
package_set = set()
merged_graph = nx.DiGraph()
workbook = openpyxl.load_workbook(excel_file)
sheet = workbook.active

#找到目标软件列表
names=[]
for cell in sheet['A']:
    value = str(cell.value)
    names.append(value)

#构件图
for folder_name in os.listdir(recipes_folder_path):
    if folder_name in names:
        build_graph(folder_name)
#画出图
pos = nx.circular_layout(merged_graph)
plt.figure(figsize=(30, 30))
#绘制图形
nx.draw_networkx(merged_graph, pos, with_labels=True, node_size=100)
#显示图形
plt.show()

print("节点数：",merged_graph.number_of_nodes())
while True:
    updated_nodes_with_zero_outdegree = [node for node in merged_graph.nodes if merged_graph.out_degree(node) == 0]
    if len(updated_nodes_with_zero_outdegree) == 0:
        break
    print(updated_nodes_with_zero_outdegree)
    print(len(updated_nodes_with_zero_outdegree))
    merged_graph.remove_nodes_from(updated_nodes_with_zero_outdegree)